package com.wanxing.sellerapp.seller;

import com.device.utils.SnowflakeIdWorker;
import com.wanxing.sellerapp.config.SellerConfig;

import java.util.Arrays;

/**
 * 秤
 */
public class Scale {

    public interface OnErrorCallback {
        void onError(boolean valueError, boolean weightError, int scaleNo, long errorId);
    }

    public interface OnWeightChangeCallback{
        void onWeightChange(int scaleNo, int weight);
    }

    public interface OnReadNewestStableWeight {
        void onRead(int scaleNo, int weight);
    }


    private OnErrorCallback mErrorCallback;

    private OnReadNewestStableWeight mOnReadNewestStableWeight;

    private OnWeightChangeCallback mOnWeightChangeCallback;

    private long errorId = Long.MIN_VALUE;

    /**
     * 秤编号 1-10
     */
    private int scaleNo;

    /**
     * 当前秤重量
     */
    private int currentWeight;

    /**
     * 稳定重量
     */
    private int stableWeight;
    /**
     * 获取到稳定重量的系统时间催
     */
    private long stableWeightWhen;

    /**
     * 请求获取稳定重量的时间
     */
    private long reqStableWeightWhen;


    /**
     * 检测错误
     */
    private boolean checkError;

    /**
     * 最小重量异常
     */
    private boolean weightValueError = false;

    /**
     * 重量波动异常
     */
    private boolean weightChangeError = false;

    /**
     * 最近重量变化，根据该变化量来确定称是否正常
     */
    private final int[] recentChange = new int[50];

    // 采样数据
    private final int[] sampleWeight = new int[SellerConfig.SAMPLE_DATA_SIZE];

    public Scale(){}
    public Scale(int scaleNo) {
        this.scaleNo = scaleNo;
    }




    public void setErrorCallback(OnErrorCallback callback) {
        this.mErrorCallback = callback;
    }

    public void setNewWeight(int weight) {
        int changeWeight  = weight - currentWeight;
        if (checkError) {
            pushDataToArrayTail(recentChange, changeWeight);
            int errorSize = 0;
            for (int change : recentChange) {
                if (Math.abs(change) >= SellerConfig.ACCEPT_WEIGHT_CHANGE) {
                    if (++errorSize > SellerConfig.JUDGE_ERROR_CHANGE_SIZE) {
                        break;
                    }
                }
            }
            weightChangeError = ++errorSize > SellerConfig.JUDGE_ERROR_CHANGE_SIZE;
        }
        //保存当前重量
        currentWeight = weight;
        // 秤重量发生变化
        if (Math.abs(changeWeight) >= SellerConfig.ACCEPT_WEIGHT_CHANGE) {
            mOnWeightChangeCallback.onWeightChange(scaleNo, weight);
        }

        // 当已经检测到秤变化异常的时候获取计算稳定重量已经没有意义，直接给未处理的重量即可
        if (weightChangeError){
            stableWeight = weight;
            stableWeightWhen = System.currentTimeMillis();
        } else {
            //若当前重量和缓存的数据中
            int stableSize = 0;
            for (int w : sampleWeight) {
                if (Math.abs(w - currentWeight) <= SellerConfig.ACCEPT_STABLE_WEIGHT_ERROR) {
                    if (++stableSize >= SellerConfig.SAMPLE_DATA_CORRECT_SIZE) {
                        stableWeight = weight;
                        stableWeightWhen = System.currentTimeMillis();
                        weightValueError = stableWeight <= SellerConfig.JUDGE_ERROR_MIN_WIGHT || stableSize >= SellerConfig.JUDGE_ERROR_MAX_WIGHT;
                        break;
                    }
                }
            }
        }
        // 返回延迟读取重量信息
        if (mOnReadNewestStableWeight != null) {
            if (reqStableWeightWhen <= stableWeightWhen) {
                mOnReadNewestStableWeight.onRead(scaleNo, stableWeight);
                mOnReadNewestStableWeight = null;
            }
        }
        pushDataToArrayTail(sampleWeight, weight);
        if (checkError) {
            if (weightChangeError || weightValueError) {
                //上次异常已处理或第一次产生异常, 通知异常
                if (errorId == Long.MIN_VALUE){
                    if (mErrorCallback != null){
                        errorId = SnowflakeIdWorker.getInstance().nextId();
                        mErrorCallback.onError(weightValueError, weightChangeError, scaleNo, errorId);
                    }
                }
                else {
                    //上次异常还未得到处理，不进行业务逻辑
                }
            } else {
                // 异常已经处理，清除异常
                errorId = Long.MIN_VALUE;
            }
        }
    }

    private void pushDataToArrayTail(int[] array, int data) {
        for (int i = 0; i < array.length - 1; i++) {
            array[i] = array[i + 1];
        }
        array[array.length - 1] = data;
    }

    public int getScaleNo() {
        return scaleNo;
    }

    public int getStableWeight() {
        return stableWeight;
    }

    /**
     * 延迟获取稳定重量
     * @param callback 获取到的回调
     * @param delayMill 延迟时间(毫秒)
     */
    public void getStableWeightDelay(OnReadNewestStableWeight callback, int delayMill){
        reqStableWeightWhen  = System.currentTimeMillis() + delayMill;
        if (reqStableWeightWhen <= stableWeightWhen) {
            callback.onRead(scaleNo, stableWeight);
        } else {
            mOnReadNewestStableWeight = callback;
        }
    }

    public int getCurrentWeight() {
        return currentWeight;
    }


    public void setCheckError(boolean checkError) {
        // 改变检测错误时，清除异常
        Arrays.fill(recentChange, Integer.MIN_VALUE);
        this.checkError = checkError;
    }

    public void setOnWeightChangeCallback(OnWeightChangeCallback onWeightChangeCallback) {
        this.mOnWeightChangeCallback = onWeightChangeCallback;
    }
}
